﻿#include "board.h"
#include "lpiece.h"
#include "ipiece.h"
#include "lmpiece.h"
#include "lpiece.h"
#include "nmpiece.h"
#include "npiece.h"
#include "qpiece.h"
#include "tpiece.h"
#include "level.h"
#include <cmath>
#include <QMessageBox>

Board::Board():QGraphicsScene(),m_Score(0),m_GameOver(false), m_Level(Level())
{
    srand(time(0));
    for (int i=0; i<s_VSqm; i++)
    {
        for (int j=0; j<s_HSqm; j++)
        {
            m_Map[i][j].first=false;
            m_Map[i][j].second=QColor("white");
        }
    }
    m_PecaAtual = getRandPiece(randPieceIndex());
    m_NextPieceIndex = randPieceIndex();
    m_NextPiece = getRandPiece(m_NextPieceIndex);
    m_NextPieceScene = new QGraphicsScene();
    setImageBackground();
}

Board::~Board()
{
    if(m_PecaAtual != NULL) delete m_PecaAtual;
    if(m_NextPiece != NULL) delete m_NextPiece;
    if(m_NextPieceScene != NULL) delete m_NextPieceScene;
}

void Board::clearData()
{
    clear();
    if(m_PecaAtual != NULL) delete m_PecaAtual;
    m_PecaAtual = NULL;
    m_GameOver = false;
    m_Level.setLevel(1);
    m_Score = 0;
    for (int i=0; i<s_VSqm; i++)
    {
        for (int j=0; j<s_HSqm; j++)
        {
            m_Map[i][j].first = false;
            m_Map[i][j].second = QColor("white");
        }
    }
}

void Board::checkBoardEmpty()
{
   bool empty = true;
   int i = 0, j = 0;
   while (empty && i<s_VSqm)
   {
       while (empty && j<s_HSqm)
       {
           if (m_Map[i][j].first)
               empty = false;
           j++;
       }
       j = 0;
       i++;
   }
   if (empty)
       m_Score += m_Level.getScoreBonus();
}

void Board::checkLinhasCompletas()
{
    int score = 0;
    for(int i=s_VSqm; i>0; i--)
        if(m_Map[i][0].first && m_Map[i][1].first &&  m_Map[i][2].first && m_Map[i][3].first &&
         m_Map[i][4].first && m_Map[i][5].first && m_Map[i][6].first && m_Map[i][7].first &&
         m_Map[i][8].first && m_Map[i][9].first)
        {
            tiraLinhaCompleta(i);
            score++;
            i++;
        }
     m_Score += score*score*m_Level.getScoreLinhaCompleta();
}

void Board::tiraLinhaCompleta(int linha)
{
    for(int i=linha; i>0; i--)
        for(int k=0 ; k<s_HSqm;k++)
            m_Map[i][k] = m_Map[i-1][k];
    redesenheBoard();
}

void Board::setImage(QImage img)
{
    QBrush back(img);
    setBackgroundBrush(back);
}

void Board::setImageBackground()
{ 
    if(isGameOver())
    {
        setImage(QImage("D:/Documents/Qtrojects/Tetris/imag/gameOver"));
    }else{
        int temp = rand() % 5;
        switch(temp)
        {
            case 0:
                setImage(QImage("D:/Documents/Qtrojects/Tetris/imag/tetris1"));
                break;
            case 1:
               setImage(QImage("D:/Documents/Qtrojects/Tetris/imag/tetris2"));
               break;
            case 2:
                setImage(QImage("D:/Documents/Qtrojects/Tetris/imag/tetris3"));
                break;
            case 3:
                setImage(QImage("D:/Documents/Qtrojects/Tetris/imag/tetris4"));
                break;
            case 4:
                setImage(QImage("D:/Documents/Qtrojects/Tetris/imag/tetris5"));
                break;
        };
    }
}
void Board::randPiece()
{
    if(m_PecaAtual != NULL)
      delete m_PecaAtual;

    if(m_NextPiece != NULL)
      delete m_NextPiece;

    if (m_Map[0][3].first || m_Map[0][4].first || m_Map[0][5].first || m_Map[0][6].first)
    {
        m_NextPiece = NULL;
        m_PecaAtual = NULL;
        if (!m_GameOver)
        {
            m_GameOver = true;
            setImageBackground();
        }
    }
    else
    {
        m_PecaAtual = getRandPiece(m_NextPieceIndex);
        for(int i=0;i < 3;++i) m_PecaAtual->moveRight();
        m_NextPieceIndex = randPieceIndex();
        m_NextPiece = getRandPiece(m_NextPieceIndex);
        m_NextPiece->centerPieceWidth(109);
        m_NextPiece->centerPieceHeight(62);
        redesenheBoard();
    }
}

void Board::redesenheBoard()
{
    if(m_PecaAtual == NULL)
      randPiece();
    clear();
    for (int i=0; i < m_PecaAtual->getQuadCount(); i++)
      addRect(m_PecaAtual->getQuadrado(i),QPen(Qt::SolidLine),QBrush(m_PecaAtual->getColor()));

    if(m_NextPiece != NULL){
        m_NextPieceScene->clear();
        for (int i=0; i < m_NextPiece->getQuadCount(); i++)
          m_NextPieceScene->addRect(m_NextPiece->getQuadrado(i),QPen(Qt::SolidLine),QBrush(m_NextPiece->getColor()));
    }

    for (int i=0; i<s_VSqm; i++)
    {
        for (int j=0; j<s_HSqm; j++)
        {
            if (m_Map[i][j].first==true)
            {
                int t = Piece::getQuadLength().height();
                addRect(j*t,i*t,t,t,QPen(Qt::SolidLine),QBrush(m_Map[i][j].second));
            }
        }
    }
}

void Board::tryMoveLeft()
{
    if(m_PecaAtual == NULL)
      randPiece();
    QList<QRect> quads = m_PecaAtual->getQuadrados();
    if(!checkLeftCollision(quads))
    {
        m_PecaAtual->moveLeft();
        redesenheBoard();
    }
}

void Board::tryMoveRight()
{
    QList<QRect> quads = m_PecaAtual->getQuadrados();
    if(!checkRightCollision(quads))
    {
        m_PecaAtual->moveRight();
        redesenheBoard();
    }
}

void Board::tryMoveDown()
{
   QList<QRect> quads = m_PecaAtual->getQuadrados();
   if(!checkDownCollision(quads))
   {
        m_PecaAtual->moveDown();
        redesenheBoard();
   }
    else
    {
        checkLinhasCompletas();
        checkBoardEmpty();
        m_Score += m_Level.getScoreNovaPeca();
        while (m_Score >= m_Level.getScoreToNextLevel())
        {
            m_Level.setLevel(m_Level.getLevelValue()+1);
            setImageBackground();
        }

        randPiece();
    }
}

void Board::tryRotation()
{
    if(m_PecaAtual == NULL)
      randPiece();
    QList<QRect> quads = m_PecaAtual->rotacione();
    if(!checkOverlap(quads)){
        m_PecaAtual->setQuadrados(quads);
        redesenheBoard();
    }
}

bool Board::checkLeftCollision(QList<QRect> &quads)
{
    bool ret = false;
    int t = Piece::getQuadLength().width();

    for (int i=0; i < quads.size(); i++)
        if (m_Map[quads[i].y()/t][(quads[i].x()-t)/t].first)
            ret = true;

    for(int i=0; i < quads.size();i++)
        if(quads[i].x() <= 0)
            ret = true;

    return ret;
}

bool Board::checkRightCollision(QList<QRect> &quads)
{
    bool ret = false;
    int t = Piece::getQuadLength().width();

    for (int i=0; i < quads.size();i++)
        if (m_Map[quads[i].y()/t][(quads[i].x()+t)/t].first)
            ret = true;

    for(int i=0; i < quads.size();i++)
        if((quads[i].x()+t) >= s_maxX)
          ret = true;

    return ret;
}

bool Board::checkDownCollision(QList<QRect> &quads)
{
    bool ret = false;
    int t = Piece::getQuadLength().height();

    for (int i=0; i < quads.size(); i++)
        if (m_Map[(quads[i].y()+t)/t][quads[i].x()/t].first)
            ret = true;

    for(int i=0; i < quads.size();i++)
        if(((quads[i].y()+t) >= s_maxY) || ret)
        {
            for (int i=0; i < quads.size(); i++)
            {
                m_Map[quads[i].y()/t][quads[i].x()/t].first = true;
                m_Map[quads[i].y()/t][quads[i].x()/t].second = m_PecaAtual->getColor();
            }
            ret = true;
        }

    return ret;
}

bool Board::checkOverlap(QList<QRect> &quads)
{
    bool ret = false;
    int t = Piece::getQuadLength().height();

    /*!< sobreposição para retângulos já preenchidos na board */
    for (int i=0; i < quads.size(); i++)
        if (m_Map[quads[i].y()/t][quads[i].x()/t].first)
            ret = true;

    /*!< sobreposição para limite da esquerda */
    for(int i=0; i < quads.size();i++)
        if(quads[i].x() <= (0 - t))
            ret = true;

    /*!< sobreposição para limite da direita */
    for(int i=0; i < quads.size();i++)
        if((quads[i].x()+t) >= (s_maxX + t))
          ret = true;

    /*!< sobreposição para limite inferior */
    for(int i=0; i < quads.size();i++)
        if(((quads[i].y()+t) >= (s_maxY + t)) || ret)
          ret = true;

    return ret;
}

int Board::randPieceIndex(){
    return (rand() % 69) / 10;
}

Piece* Board::getRandPiece(int piece){
    switch(piece)
    {
        case 0:
            return (new LPiece());
        case 1:
            return (new IPiece());
        case 2:
            return (new LMPiece());
        case 3:
            return (new NMPiece());
        case 4:
            return (new NPiece());
        case 5:
            return (new QPiece());
        default:
            return (new TPiece());
    }
}
